package com.vhall.component.service.exam.tasks;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.exam.ExamAnswersMapper;
import com.vhall.component.dao.exam.ExamMapper;
import com.vhall.component.dao.exam.ExamRoomLkMapper;
import com.vhall.component.entity.exam.ExamAnswerEntity;
import com.vhall.component.entity.exam.ExamEntity;
import com.vhall.component.entity.exam.vo.ExamAnswerReqVo;
import com.vhall.component.entity.room.RoomExamLkEntity;
import com.vhall.component.entity.room.dto.RoomJoinsEntityDTO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.service.room.RoomInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.connection.stream.ObjectRecord;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.stream.StreamListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Redis 队列消息订阅
 *
 * @author guoxin.wang
 * @date 2021/6/11
 */
@Slf4j
@Lazy
@Component
public class ExamMsgStreamListener implements StreamListener<String, ObjectRecord<String, String>> {

    @Value("${vhall.exam.group-name:exam-group}")
    private String groupName;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RoomInnerService roomInnerService;

    @Autowired
    private ExamRoomLkMapper examRoomLkMapper;

    @Autowired
    private ExamAnswersMapper examAnswersMapper;

    @Autowired
    private ExamMapper examMapper;

    private static final String JSON_ARRAY_TYPE_STR = "com.alibaba.fastjson.JSONArray";

    private static final String ANSWER_RESULT_KEY = "answerResult";

    private static final String ELECT_SCORE_KEY = "electScore";

    private static final String TOTAL_NUM_KEY = "totalNum";

    private static final String CORRECT_INDEX_KEY = "correctIndex";

    private static final String SCORE_KEY = "score";

    private static final String REPLYS_KEY = "replys";

    @Autowired
    private ExamMsgStreamListener self;


    @Override
    public void onMessage(ObjectRecord<String, String> message) {
        // 消息ID
        RecordId messageId = message.getId();
        // 消息的key和value
        log.info("[考试组件]接收到回答Stream消息,messageId={}, stream={}, body={}",
                messageId, message.getStream(), message.getValue());
        // 开始处理消息的逻辑
        String value = message.getValue();
        if (StringUtils.isNotEmpty(value)) {
            self.saveAnswer(value);
        }
        // 通过RedisTemplate手动确认消息
        redisTemplate.opsForStream().acknowledge(groupName, message);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAnswer(String value) {
        // 消费 添加考试回答明细,
        ExamAnswerReqVo param = JSON.parseObject(value, ExamAnswerReqVo.class);
        RoomJoinsEntityDTO joinUser = roomInnerService.getRoomJoinInfo(param.getAccountId(), String.valueOf(param.getRoomId()));
        if (null == joinUser) {
            throw new BusinessException(BizErrorCode.AUTH_LOGIN_NO_PERMISSION);
        }
        if (param.getStartTime() == null) {
            LambdaQueryWrapper<RoomExamLkEntity> query = Wrappers.lambdaQuery();
            query.eq(RoomExamLkEntity::getRoomId, param.getRoomId());
            query.eq(RoomExamLkEntity::getExamId, param.getExamId());
            RoomExamLkEntity lk = examRoomLkMapper.selectOne(query);
            if (lk != null) {
                param.setStartTime(Long.valueOf(lk.getPublishTime()));
            }
        }
        log.info("queueAnswerParams是{}", param);
        ExamAnswerEntity entity = new ExamAnswerEntity();
        entity.setAnswerId(param.getAnswerId());
        // 处理extend信息
        String extend = "";
        if (StringUtils.isNotBlank(param.getExtend()) && !Objects.equals("[]", param.getExtend())) {
            extend = dealExtend(param.getExtend());
            param.setExtend(extend);
            Map<String, Object> extendArr = JSON.parseObject(extend, Map.class);
            JSONObject answerResult = (JSONObject) extendArr.get(ANSWER_RESULT_KEY);
            if (StringUtils.isNotBlank((String) answerResult.get(ELECT_SCORE_KEY))) {
                entity.setElectScore(Integer.valueOf((String) answerResult.get(ELECT_SCORE_KEY)));
                entity.setAnswererScore(Integer.valueOf((String) answerResult.get(ELECT_SCORE_KEY)));
            }
            ExamEntity exam = getExam(param.getExamId(), null);
            //判断是否为系统自动批阅
            if (((String) answerResult.get(TOTAL_NUM_KEY)).equals(exam.getQuestionNum().toString())) {
                entity.setIsGraded(1);
                entity.setOperatorNickName("自动批阅");
            }
        }
        LocalDateTime now = LocalDateTime.now();
        entity.setJoinId(joinUser.getJoinId());
        entity.setRoomId(String.valueOf(param.getRoomId()));
        entity.setExamId(param.getExamId());
        entity.setAccountId(param.getAccountId());
        entity.setNickname(joinUser.getNickname());
        entity.setAvatar(joinUser.getAvatar());
        entity.setOperatorAccountId(0);
        entity.setStartTime(Math.toIntExact(param.getStartTime()));
        entity.setEndTime(Math.toIntExact(param.getEndTime()));
        entity.setGradedMark("");
        entity.setExtend(extend);
        entity.setCreatedAt(now);
        entity.setUpdatedAt(now);
        entity.setAnswerId(param.getAnswerId());
        //防止重复入库
        LambdaQueryWrapper<ExamAnswerEntity> queryCount = Wrappers.lambdaQuery();
        queryCount.eq(ExamAnswerEntity::getRoomId, entity.getRoomId());
        queryCount.eq(ExamAnswerEntity::getExamId, entity.getExamId());
        queryCount.eq(ExamAnswerEntity::getAccountId, entity.getAccountId());
        Integer exists = examAnswersMapper.selectCount(queryCount);
        try {
            if (exists <= 0) {
                log.info("数据库插入成功,{}", JsonUtil.toJsonString(entity));
                examAnswersMapper.insert(entity);
            }
        } catch (Exception e) {
            log.error("数据库插入失败，错误信息为，{}", e.getMessage());
        }
        if (exists <= 0) {
            if (joinUser.getIsAnsweredExam() == 0) {
                joinUser.setIsAnsweredExam(1);
                roomInnerService.updateRoomJoinsById(joinUser);
            }
        }
    }

    private ExamEntity getExam(Integer examId, String roomId) {
        ExamEntity exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
        }
        if (StringUtils.isNotBlank(roomId)) {
            RoomsEntityDTO room = roomInnerService.getRoomsEntityInfo(roomId);
            if (room == null) {
                throw new BusinessException(BizErrorCode.EMPTY_ROOM);
            }
            if (!room.getAccountId().equals(exam.getAccountId())) {
                throw new BusinessException(BizErrorCode.COMP_EXAM_PAPER_NOT_EXIST);
            }
        }
        return exam;
    }

    /**
     * 处理考试回答内容 得出结果
     *
     * @param extend
     * @return string
     */
    private static String dealExtend(String extend) {
        String result = "";
        /*该参数格式：[{
        	"id": 649553,
        	"required": false,
        	"type": "radio",
        	"title": "请选择一下那位是中国人？",
        	"imgUrl": "",
        	"verification": false,
        	"score": 10,
        	"style": "",
        	"ext": "",
        	"extension": "exam",
        	"analysis": "",
        	"replys": "A",
        	"createDate": "2021-07-20 10:27:41",
        	"isQuote": true,
        	"custom_ques": 2,
        	"items": [{
        		"key": "A",
        		"value": "爱迪生",
        		"imgUrl": "",
        		"custom_opt": 2,
        		"custom_val": ""
        	}, {
        		"key": "B",
        		"value": "桥的麻袋",
        		"imgUrl": "",
        		"custom_opt": 2,
        		"custom_val": ""
        	}, {
        		"key": "C",
        		"value": "李时珍",
        		"imgUrl": "",
        		"custom_opt": 2,
        		"custom_val": ""
        	}],
        	"correctIndex": 2,
        	"validate": {},
        	"status": "submit"
        }]*/
        JSONArray answerContent = JSON.parseArray(extend);

        /*if (answerContent.isEmpty()) {
            result = extend;
            return result;
        }*/
        //准确率
        Integer accuracy = 0;
        //总分数
        Integer totalScore = 0;
        //得分数
        Integer electScore = 0;
        //总题目数
        Integer totalNum = 0;
        //答对问题数
        Integer rightNum = 0;
        //答错问题数
        Integer errNum = 0;
        //未作答问题数
        Integer emptyNum = 0;

        // 计入总分的题目的类型
        List<String> typs = new ArrayList<>();
        typs.add("radio");
        typs.add("checkbox");
        // h5端排序题类型为rank，web端为radio
        typs.add("rank");
        outer:
        for (int i = 0; i < answerContent.size(); i++) {
            JSONObject answer = (JSONObject) answerContent.get(i);
            //超出字母表的 不计入准确率和总分数
            if (answer.get(CORRECT_INDEX_KEY) != null) {
                Object correctIndex = answer.get(CORRECT_INDEX_KEY);
                // 判断单选还是多选
                Class<?> correctIndexClass = correctIndex.getClass();
                if (JSON_ARRAY_TYPE_STR.equals(correctIndexClass.getName())) {
                    // 多选
                    JSONArray correctIndex1 = (JSONArray) answer.get(CORRECT_INDEX_KEY);
                    for (int j = 0; j < correctIndex1.size(); j++) {
                        if ((int) correctIndex1.get(j) < 0 || (int) correctIndex1.get(j) > 25) {
                            continue outer;
                        }
                    }
                } else {
                    // 单选
                    if ((int) answer.get(CORRECT_INDEX_KEY) < 0 || (int) answer.get(CORRECT_INDEX_KEY) > 25) {
                        continue outer;
                    }
                }
            }
            // 是否是计入总分的题目
            String type = (String) answer.get("type");
            if (typs.contains(type)) {
                totalNum += 1;
                totalScore += (Integer) answer.get(SCORE_KEY);
            }
            // 回答内容为空 传的是[]
            Object o = answer.get(REPLYS_KEY);
            if (JSON_ARRAY_TYPE_STR.equals(o.getClass().getName())) {
                JSONArray answerMsg = (JSONArray) answer.get(REPLYS_KEY);
                if (answerMsg.size() == 0) {
                    emptyNum += 1;
                    continue outer;
                }
            }
            if (answer.get(REPLYS_KEY) == null && judge(answer.get(REPLYS_KEY))) {
                emptyNum += 1;
                continue outer;
            }
            // 统计正确答案
            switch (type) {
                // h5端排序题类型为rank，web端为radio
                case "rank":
                case "radio":
                    // 判断用户答案正确  没有预设答案 只要回复就计算分数
                    // 因为是单选所以正确答案的类型是String.
                    String replyStr = (String) answer.get(REPLYS_KEY);
                    char[] replys = replyStr.toCharArray();
                    int trueReply = (int) replys[0] - 65;
                    if (answer.get(CORRECT_INDEX_KEY) == null || trueReply == (Integer) answer.get(CORRECT_INDEX_KEY)) {
                        rightNum += 1;
                        electScore += (Integer) answer.get(SCORE_KEY);
                    } else {
                        errNum += 1;
                    }
                    break;
                case "checkbox":
                    // 因为是多选所以正确答案的类型是JSONArray.
                    JSONArray replyOfArray = (JSONArray) answer.get(REPLYS_KEY);
                    JSONArray correctIndexOfArray = (JSONArray) answer.get(CORRECT_INDEX_KEY);
                    if (correctIndexOfArray.size() == 0) {
                        rightNum += 1;
                        electScore += (Integer) answer.get(SCORE_KEY);
                        break;
                    }
                    List<String> rightReplyList = correctIndexOfArray.stream().map(s -> {
                        // 数字转换为对应的选项 例如 0->A
                        int correct1 = (Integer) s + 65;
                        char correct2 = (char) correct1;
                        return String.valueOf(correct2);
                    }).collect(Collectors.toList());
                    // 移除是为了求两个集合的差集
//                    replyOfArray.removeAll(rightReplyList);
                    List<String> replyList = replyOfArray.stream().map(String::valueOf).collect(Collectors.toList());
                    if (replyOfArray.size() == rightReplyList.size()) {
                        if (checkListDifferent(replyList, rightReplyList)) {
                            rightNum += 1;
                            electScore += (Integer) answer.get(SCORE_KEY);
                        } else {
                            errNum += 1;
                        }
                    } else {
                        errNum += 1;
                    }

//                    if (replyOfArray.size() == 0) {
//                        rightNum += 1;
//                        electScore += (Integer) answer.get(SCORE_KEY);
//                    } else {
//                        errNum += 1;
//                    }
                    break;
                default:
                    break;
            }
        }
        //计算准确率
        if (totalNum > 0) {
            accuracy = Math.round((float) rightNum / totalNum * 100);
        }
        //回答结果统计
        JSONObject answerResult = new JSONObject();
        answerResult.put(TOTAL_NUM_KEY, totalNum.toString());
        answerResult.put("rightNum", rightNum.toString());
        answerResult.put("totalScore", totalScore.toString());
        answerResult.put(ELECT_SCORE_KEY, electScore.toString());
        answerResult.put("errNum", errNum.toString());
        answerResult.put("emptyNum", emptyNum.toString());
        answerResult.put("accuracy", accuracy.toString());
        Map<String, Object> resultOfMap = new HashMap<>(4);
        resultOfMap.put("answerContent", answerContent);
        resultOfMap.put(ANSWER_RESULT_KEY, answerResult);
        result = JSON.toJSONString(resultOfMap);
        return result;
    }

    private static boolean checkListDifferent(List<String> list1, List<String> list2) {
        list1.sort(Comparator.comparing(String::hashCode));
        list2.sort(Comparator.comparing(String::hashCode));
        return list1.toString().equals(list2.toString());
    }

    /**
     * 判断提交的答案是否为空。空返回true,否则返回false;
     *
     * @param replys
     * @return
     */
    private static boolean judge(Object replys) {
        Class<?> correctIndexClass = replys.getClass();
        if (JSON_ARRAY_TYPE_STR.equals(correctIndexClass.getName())) {
            JSONArray ja = (JSONArray) replys;
            if (ja.size() == 0) {
                return true;
            }
        } else {
            String s = (String) replys;
            if (StringUtils.isEmpty(s)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
//        String value = "{\"accountId\":265363,\"answerId\":8274118,\"endTime\":1631253684,\"examId\":580892,\"extend\":\"[{\\\"id\\\":677570,\\\"type\\\":\\\"checkbox\\\",\\\"title\\\":\\\"多选题\\\",\\\"imgUrl\\\":\\\"\\\",\\\"items\\\":[{\\\"key\\\":\\\"A\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"B\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"C\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"D\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"}],\\\"correctIndex\\\":[1,2],\\\"replys\\\":[\\\"A\\\",\\\"B\\\"],\\\"score\\\":10},{\\\"id\\\":677571,\\\"type\\\":\\\"rank\\\",\\\"title\\\":\\\"排序题\\\",\\\"imgUrl\\\":\\\"\\\",\\\"items\\\":[{\\\"key\\\":\\\"A\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"B\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"}],\\\"rankItems\\\":[{\\\"value\\\":\\\"①语句\\\",\\\"key\\\":\\\"0\\\",\\\"imgUrl\\\":\\\"\\\"},{\\\"value\\\":\\\"②语句\\\",\\\"key\\\":\\\"1\\\",\\\"imgUrl\\\":\\\"\\\"}],\\\"correctIndex\\\":0,\\\"replys\\\":\\\"A\\\",\\\"score\\\":10}]\",\"roomId\":\"lss_c6eabb3f\",\"startTime\":1631253674}";
        String value = "{\"accountId\":270022,\"answerId\":8313070,\"endTime\":1631590151,\"examId\":581245,\"extend\":\"[{\\\"id\\\":678622,\\\"required\\\":false,\\\"type\\\":\\\"checkbox\\\",\\\"title\\\":\\\"多选题\\\",\\\"imgUrl\\\":\\\"\\\",\\\"verification\\\":false,\\\"score\\\":10,\\\"style\\\":\\\"\\\",\\\"ext\\\":\\\"\\\",\\\"extension\\\":\\\"exam\\\",\\\"analysis\\\":\\\"\\\",\\\"replys\\\":[\\\"A\\\",\\\"B\\\"],\\\"createDate\\\":\\\"2021-09-14 11:28:54\\\",\\\"isQuote\\\":true,\\\"custom_ques\\\":2,\\\"items\\\":[{\\\"key\\\":\\\"A\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"B\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"C\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"D\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"}],\\\"correctIndex\\\":[0,1],\\\"validate\\\":{},\\\"status\\\":\\\"submit\\\"},{\\\"id\\\":678623,\\\"required\\\":false,\\\"type\\\":\\\"radio\\\",\\\"title\\\":\\\"排序题\\\",\\\"imgUrl\\\":\\\"\\\",\\\"verification\\\":false,\\\"score\\\":10,\\\"style\\\":\\\"\\\",\\\"ext\\\":{\\\"rank\\\":true,\\\"rankItems\\\":[{\\\"value\\\":\\\"①语句\\\",\\\"key\\\":\\\"0\\\",\\\"imgUrl\\\":\\\"\\\"},{\\\"value\\\":\\\"②语句\\\",\\\"key\\\":\\\"1\\\",\\\"imgUrl\\\":\\\"\\\"}]},\\\"extension\\\":\\\"exam\\\",\\\"analysis\\\":\\\"\\\",\\\"replys\\\":\\\"A\\\",\\\"createDate\\\":\\\"2021-09-14 11:28:54\\\",\\\"isQuote\\\":false,\\\"custom_ques\\\":2,\\\"items\\\":[{\\\"key\\\":\\\"A\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"},{\\\"key\\\":\\\"B\\\",\\\"value\\\":\\\"选项\\\",\\\"imgUrl\\\":\\\"\\\",\\\"custom_opt\\\":2,\\\"custom_val\\\":\\\"\\\"}],\\\"correctIndex\\\":0,\\\"validate\\\":{},\\\"status\\\":\\\"submit\\\"}]\",\"roomId\":\"lss_c6eabb3f\",\"startTime\":1631590142}";
        ExamAnswerReqVo param = JSON.parseObject(value, ExamAnswerReqVo.class);
//        saveAnswer()
        String extend = dealExtend(param.getExtend());
        param.setExtend(extend);
        Map<String, Object> extendArr = JSON.parseObject(extend, Map.class);
        JSONObject answerResult = (JSONObject) extendArr.get(ANSWER_RESULT_KEY);
        if (StringUtils.isNotBlank((String) answerResult.get(ELECT_SCORE_KEY))) {
            /*entity.setElectScore(Integer.valueOf((String) answerResult.get("electScore")));
            entity.setAnswererScore(Integer.valueOf((String) answerResult.get("electScore")));*/
        }
        // ExamEntity exam = getExam(param.getExamId(), null);
        //判断是否为系统自动批阅
        if ("1".equals((String) answerResult.get(TOTAL_NUM_KEY))) {
            /*entity.setIsGraded(1);
            entity.setOperatorNickName("自动批阅");*/
        }
    }

}
